#include "s_st7789v.h"

//////////////////////////////////////////////////////////////////////////////////
#define FREERTOS_ENABLE                           1
#define S_ST7789V_SLPIN                           0x10
#define S_ST7789V_SLPOUT                          0x11

#define S_ST7789V_DISPOFF                         0x28
#define S_ST7789V_DISPON                          0x29

#define S_ST7789V_CASET                           0x2A
#define S_ST7789V_RASET                           0x2B

#define S_ST7789V_RAMWR                           0x2C

#define S_ST7789V_MADCTL                          0x36
#define S_ST7789V_MADCTL_Normal                          0x00
#define S_ST7789V_MADCTL_Y_MIRROR                        0x20
#define S_ST7789V_MADCTL_X_MIRROR                        0x40
#define S_ST7789V_MADCTL_X_MIRROR_Y_MIRROR               0x60
#define S_ST7789V_MADCTL_X_Y_EXCHANGE                    0x80
#define S_ST7789V_MADCTL_X_Y_EXCHANGE_Y_MIRROR           0xA0
#define S_ST7789V_MADCTL_X_Y_EXCHANGE_X_MIRROR           0xC0
#define S_ST7789V_MADCTL_X_Y_EXCHANGE_X_MIRROR_Y_MIRROR  0xE0

#define S_ST7789V_COLMOD                          0x3A

//Table 2
#define S_ST7789V_PORCTRL                         0XB2

#define S_ST7789V_GCTRL                           0XB7

#define S_ST7789V_VCOMS                           0XBB

#define S_ST7789V_LCMCTRL                         0XC0

#define S_ST7789V_VDVVRHEN                        0XC2
#define S_ST7789V_VRHS                            0XC3
#define S_ST7789V_VDVSET                          0XC4

#define S_ST7789V_FRCTR2                          0XC6

#define S_ST7789V_PWCTL1                          0XD0

#define S_ST7789V_PVGAMCTRL                       0XE0
#define S_ST7789V_NVGAMCTRL                       0XE1
//////////////////////////////////////////////////////////////////////////////////

static s_st7789v_status s_st7789v_check(s_st7789v_t *st7789v)
{
    return s_st7789v_ok;
}

void s_st7789v_send_cmd(s_st7789v_t *st7789v, unsigned char cmd)
{
    st7789v->set_cs(s_st7789v_gpio_low);
    st7789v->set_rs(s_st7789v_gpio_low);
    st7789v->set_wr(s_st7789v_gpio_low);
    st7789v->write_u16((unsigned short)(cmd | 0xFF00));
    st7789v->set_wr(s_st7789v_gpio_high);
    st7789v->set_rs(s_st7789v_gpio_high);
    st7789v->set_cs(s_st7789v_gpio_high);
}

void s_st7789v_send_data(s_st7789v_t *st7789v, unsigned short data)
{
    st7789v->set_cs(s_st7789v_gpio_low);
    st7789v->set_rs(s_st7789v_gpio_high);
    st7789v->set_wr(s_st7789v_gpio_low);
    // st7789v->write_u16((unsigned short)(data | 0xFF00));
    st7789v->write_u16(data);
    st7789v->set_wr(s_st7789v_gpio_high);
    // st7789v->set_rs(s_st7789v_gpio_high);
    st7789v->set_cs(s_st7789v_gpio_high);
}


void s_st7789v_set_sleep_mode(s_st7789v_t *st7789v, s_st7789v_sleep_mode mode)
{
    if(s_st7789v_sleep_enable == mode)
    {
        s_st7789v_send_cmd(st7789v, S_ST7789V_SLPIN);
    }
    else
    {
        s_st7789v_send_cmd(st7789v, S_ST7789V_SLPOUT);
    }
    st7789v->delay(10);
}

void s_st7789v_set_display_mode(s_st7789v_t *st7789v, s_st7789v_display_mode mode)
{
    if(s_st7789v_display_on == mode)
    {
        s_st7789v_send_cmd(st7789v, S_ST7789V_DISPON);
    }
    else
    {
        s_st7789v_send_cmd(st7789v, S_ST7789V_DISPOFF);
    }
    st7789v->delay(10);
}

void s_st7789v_reset(s_st7789v_t *st7789v)
{
    st7789v->set_rst(s_st7789v_gpio_high);
    st7789v->set_rst(s_st7789v_gpio_low);
    st7789v->delay(10);
    st7789v->set_rst(s_st7789v_gpio_high);
    st7789v->delay(50);
}

void s_st7789v_set_column_addr(s_st7789v_t *st7789v, unsigned short start, unsigned short end)
{
    s_st7789v_send_cmd(st7789v, S_ST7789V_CASET);
    s_st7789v_send_data(st7789v, start >> 8);
    s_st7789v_send_data(st7789v, 0xFF00 | start);
    s_st7789v_send_data(st7789v, end >> 8);
    s_st7789v_send_data(st7789v, 0xFF00 | end);
}

void s_st7789v_set_row_addr(s_st7789v_t *st7789v, unsigned short start, unsigned short end)
{
    s_st7789v_send_cmd(st7789v, S_ST7789V_RASET);
    s_st7789v_send_data(st7789v, start >> 8);
    s_st7789v_send_data(st7789v, 0xFF00 | start);
    s_st7789v_send_data(st7789v, end >> 8);
    s_st7789v_send_data(st7789v, 0xFF00 | end);
}

void s_st7789v_fillall(s_st7789v_t *st7789v, unsigned short width, unsigned short height, unsigned short color)
{
	unsigned short i, j;
	s_st7789v_set_column_row_addr(st7789v, 0, width - 1, 0, height - 1);
	
	s_st7789v_send_cmd(st7789v, S_ST7789V_RAMWR);
	for(i = 0U; i < width; i++)
	{
		for(j = 0U; j < height; j++)
		{
			s_st7789v_send_data(st7789v, color);
		}
	}
}

s_st7789v_status s_st7789v_init(s_st7789v_t *st7789v)
{
    if(s_st7789v_check(st7789v) != s_st7789v_ok)
    {
        return s_st7789v_check_failed;
    }

    st7789v->set_rs(s_st7789v_gpio_high);
    st7789v->set_cs(s_st7789v_gpio_high);
    st7789v->set_rd(s_st7789v_gpio_high);
    st7789v->set_wr(s_st7789v_gpio_high);
    st7789v->set_rst(s_st7789v_gpio_high);
    st7789v->set_bl(s_st7789v_gpio_high);

    s_st7789v_reset(st7789v);
    s_st7789v_set_sleep_mode(st7789v, s_st7789v_sleep_disable);

    s_st7789v_send_cmd(st7789v, S_ST7789V_MADCTL);
    s_st7789v_send_data(st7789v, S_ST7789V_MADCTL_Normal);


    s_st7789v_send_cmd(st7789v, S_ST7789V_COLMOD);
    s_st7789v_send_data(st7789v, 0x05);

    s_st7789v_send_cmd(st7789v, S_ST7789V_PORCTRL);
    s_st7789v_send_data(st7789v, 0x0c);
    s_st7789v_send_data(st7789v, 0x0c);
    s_st7789v_send_data(st7789v, 0x00);
    s_st7789v_send_data(st7789v, 0x33);
    s_st7789v_send_data(st7789v, 0x33);

    s_st7789v_send_cmd(st7789v, S_ST7789V_GCTRL);
    s_st7789v_send_data(st7789v, 0x35); //VGH=13V, VGL=-10.4V

    s_st7789v_send_cmd(st7789v, S_ST7789V_VCOMS);
    s_st7789v_send_data(st7789v, 0x16);

    s_st7789v_send_cmd(st7789v, S_ST7789V_LCMCTRL);
    s_st7789v_send_data(st7789v, 0x2c);

    s_st7789v_send_cmd(st7789v, S_ST7789V_VDVVRHEN);
    s_st7789v_send_data(st7789v, 0x01);

    s_st7789v_send_cmd(st7789v, S_ST7789V_VRHS);
    s_st7789v_send_data(st7789v, 0x13);

    s_st7789v_send_cmd(st7789v, S_ST7789V_VDVSET);
    s_st7789v_send_data(st7789v, 0x20);

    s_st7789v_send_cmd(st7789v, S_ST7789V_FRCTR2);
    s_st7789v_send_data(st7789v, 0x0f);

    s_st7789v_send_cmd(st7789v, S_ST7789V_PWCTL1);
    s_st7789v_send_data(st7789v, 0xa4);
    s_st7789v_send_data(st7789v, 0xa1);

    s_st7789v_send_cmd(st7789v, S_ST7789V_PVGAMCTRL); 
    s_st7789v_send_data(st7789v, 0xd0);
    s_st7789v_send_data(st7789v, 0x04);
    s_st7789v_send_data(st7789v, 0x10);
    s_st7789v_send_data(st7789v, 0x13);
    s_st7789v_send_data(st7789v, 0x14);
    s_st7789v_send_data(st7789v, 0x2c);
    s_st7789v_send_data(st7789v, 0x41);
    s_st7789v_send_data(st7789v, 0x54);
    s_st7789v_send_data(st7789v, 0x4e);
    s_st7789v_send_data(st7789v, 0x18);
    s_st7789v_send_data(st7789v, 0x0c);
    s_st7789v_send_data(st7789v, 0x0a);
    s_st7789v_send_data(st7789v, 0x21);
    s_st7789v_send_data(st7789v, 0x25);

    s_st7789v_send_cmd(st7789v, S_ST7789V_NVGAMCTRL);
    s_st7789v_send_data(st7789v, 0xd0);
    s_st7789v_send_data(st7789v, 0x04);
    s_st7789v_send_data(st7789v, 0x0f);
    s_st7789v_send_data(st7789v, 0x13);
    s_st7789v_send_data(st7789v, 0x15);
    s_st7789v_send_data(st7789v, 0x2c);
    s_st7789v_send_data(st7789v, 0x40);
    s_st7789v_send_data(st7789v, 0x44);
    s_st7789v_send_data(st7789v, 0x52);
    s_st7789v_send_data(st7789v, 0x2d);
    s_st7789v_send_data(st7789v, 0x1d);
    s_st7789v_send_data(st7789v, 0x1e);
    s_st7789v_send_data(st7789v, 0x21);
    s_st7789v_send_data(st7789v, 0x24);

    s_st7789v_set_display_mode(st7789v, s_st7789v_display_on);

    // s_st7789v_fillall(st7789v, unsigned short width, unsigned short height, 0xFFFF);


    return s_st7789v_ok;
}